package com.weimob.mcloud.wechatwork.customer.service.impl;

import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.weimob.mcloud.wechatwork.common.utils.JsonUtil;
import com.weimob.mcloud.wechatwork.core.adapter.enums.uc.UCSourceTypeEnum;
import com.weimob.mcloud.wechatwork.core.adapter.pojo.dto.bos.response.ProductInstanceDTO;
import com.weimob.mcloud.wechatwork.core.adapter.pojo.dto.cdp.request.base.CdpRequest;
import com.weimob.mcloud.wechatwork.core.adapter.pojo.dto.cdp.request.tag.CustomerTagAdapterDTO;
import com.weimob.mcloud.wechatwork.core.adapter.pojo.dto.cdp.request.tag.TagAdapterDTO;
import com.weimob.mcloud.wechatwork.core.adapter.pojo.dto.cdp.request.tag.TagGroupAdapterDTO;
import com.weimob.mcloud.wechatwork.core.adapter.pojo.dto.channel.response.CorpTagGroup;
import com.weimob.mcloud.wechatwork.core.adapter.pojo.dto.channel.response.CorpTagInfo;
import com.weimob.mcloud.wechatwork.core.adapter.pojo.dto.channel.response.FollowUserBO;
import com.weimob.mcloud.wechatwork.core.adapter.pojo.dto.channel.response.SelfExternalContactGetBO;
import com.weimob.mcloud.wechatwork.core.adapter.pojo.dto.onecrm.request.AccountGetDTO;
import com.weimob.mcloud.wechatwork.core.adapter.pojo.dto.onecrm.response.AccountGetBO;
import com.weimob.mcloud.wechatwork.core.adapter.service.OneCrmAdapterService;
import com.weimob.mcloud.wechatwork.core.adapter.service.cdp.CdpTagAdapterServiceV2;
import com.weimob.mcloud.wechatwork.core.base.MultiResponse;
import com.weimob.mcloud.wechatwork.core.base.SingleRequest;
import com.weimob.mcloud.wechatwork.core.entity.privatesphere.PrivateSphere;
import com.weimob.mcloud.wechatwork.core.entity.relation.customer.ActionLog;
import com.weimob.mcloud.wechatwork.core.entity.relation.customer.Customer;
import com.weimob.mcloud.wechatwork.core.entity.relation.employee.Employee;
import com.weimob.mcloud.wechatwork.core.entity.relation.tag.MarkTagDetail;
import com.weimob.mcloud.wechatwork.core.entity.relation.tag.MarkTagTask;
import com.weimob.mcloud.wechatwork.core.entity.relation.tag.Tag;
import com.weimob.mcloud.wechatwork.core.entity.relation.tag.TagGroup;
import com.weimob.mcloud.wechatwork.core.enums.customer.ActionLogBizeTypeEnum;
import com.weimob.mcloud.wechatwork.core.enums.customer.ActionLogEventTypeEnum;
import com.weimob.mcloud.wechatwork.core.enums.tag.MarkTagTaskStatusEnum;
import com.weimob.mcloud.wechatwork.core.service.customer.CustomerService;
import com.weimob.mcloud.wechatwork.core.service.privatesphere.PrivateSphereService;
import com.weimob.mcloud.wechatwork.core.service.tag.TagTaskCoreService;
import com.weimob.mcloud.wechatwork.customer.constant.Constants;
import com.weimob.mcloud.wechatwork.customer.convertor.bos.PrivateSphereCovert;
import com.weimob.mcloud.wechatwork.customer.convertor.tag.TagConvert;
import com.weimob.mcloud.wechatwork.customer.convertor.tag.TagGroupConvert;
import com.weimob.mcloud.wechatwork.customer.domain.ArtemisBaseInfo;
import com.weimob.mcloud.wechatwork.customer.domain.ArtemisConstant;
import com.weimob.mcloud.wechatwork.customer.externalDependencyProxy.usermanagement.EmployeeProxy;
import com.weimob.mcloud.wechatwork.customer.facade.impl.customer.CustomerFacadeV2;
import com.weimob.mcloud.wechatwork.customer.mq.product.TagChangeMsgProduct;
import com.weimob.mcloud.wechatwork.customer.service.CustomerTagSyncService;
import com.weimob.mcloud.wechatwork.customer.service.TagBaseService;
import com.weimob.mcloud.wechatwork.customer.service.TagManageService;
import com.weimob.mcloud.wechatwork.customer.service.check.CommonCheckService;
import com.weimob.mcloud.wechatwork.customer.service.check.MarkTagTaskCheck;
import com.weimob.mcloud.wechatwork.customer.service.check.TagCheckService;
import com.weimob.mcloud.wechatwork.customer.service.user.base.BasicInfo;
import com.weimob.mcloud.wechatwork.customer.service.user.base.PrivateSphereDTO;
import com.weimob.mcloud.wechatwork.customer.service.user.constant.RedisKeyConstant;
import com.weimob.mcloud.wechatwork.customer.service.user.constant.TagConstant;
import com.weimob.mcloud.wechatwork.customer.service.user.enums.TagOperateTypeEnum;
import com.weimob.mcloud.wechatwork.customer.service.user.enums.TagSourceEnum;
import com.weimob.mcloud.wechatwork.customer.service.user.enums.tag.TagChangeEnum;
import com.weimob.mcloud.wechatwork.customer.service.user.exception.BizException;
import com.weimob.mcloud.wechatwork.customer.service.user.module.bo.tag.*;
import com.weimob.mcloud.wechatwork.customer.service.user.module.dto.customer.ExternalUserInfoFindDTO;
import com.weimob.mcloud.wechatwork.customer.service.user.module.dto.customer.MarkTagInfoDTO;
import com.weimob.mcloud.wechatwork.customer.service.user.module.dto.tag.CustomerTagDTO;
import com.weimob.mcloud.wechatwork.customer.service.user.module.dto.tag.TagDTO;
import com.weimob.mcloud.wechatwork.customer.service.user.module.dto.tag.TagGroupDTO;
import com.weimob.mcloud.wechatwork.customer.service.user.module.dto.tag.v2.MarkTagTaskMessage;
import com.weimob.mcloud.wechatwork.customer.service.user.module.req.tag.CustomerTagQueryDTO;
import com.weimob.mcloud.wechatwork.customer.service.user.module.req.tag.MarkTagDTO;
import com.weimob.mcloud.wechatwork.customer.service.user.module.req.tag.TagAddDTO;
import com.weimob.mcloud.wechatwork.customer.service.user.module.req.tag.TagQueryDTO;
import com.weimob.mcloud.wechatwork.customer.service.user.utils.SoaResponseUtil;
import com.weimob.mcloud.wechatwork.customer.third.BosThird;
import com.weimob.mcloud.wechatwork.customer.third.PrivateSphereThird;
import com.weimob.mcloud.wechatwork.customer.third.core.CustomerServiceProxy;
import com.weimob.mcloud.wechatwork.customer.third.customer.CustomerThird;
import com.weimob.mcloud.wechatwork.customer.third.tag.CdpTagThird;
import com.weimob.mcloud.wechatwork.customer.third.tag.CorpTagThird;
import com.weimob.soa.common.response.SoaResponse;
import com.weimob.soa.common.utils.SoaUtil;
import com.weimob.wechatwork.wechatworkexporter.ExportService;
import com.weimob.wechatwork.wechatworkexporter.enums.ExportTaskTypeEnum;
import com.weimob.wechatwork.wechatworkexporter.req.ExportTaskSaveDTO;
import com.weimob.wechatwork.wechatworkexporter.vo.ExportTaskSaveVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.TimeUnit;

import static com.weimob.mcloud.wechatwork.customer.service.user.enums.TagBizErrorEnum.*;

/**
 * @author junlong.lv
 * @version 1.0
 * @date 2021/10/25 3:05 下午
 */
@Slf4j
@Service
public class TagManageServiceImpl implements TagManageService {

    @Autowired
    private PrivateSphereThird privateSphereThird;

    @Autowired
    private BosThird bosThird;

    @Autowired
    private CdpTagThird cdpTagThird;

    @Autowired
    private CorpTagThird corpTagThird;

    @Autowired
    private CustomerServiceProxy customerServiceProxy;

    @Autowired
    private TagCheckService tagCheckService;

    @Autowired
    private CommonCheckService commonCheckService;

    @Autowired
    private CustomerThird customerThird;

    @Autowired
    private TagBaseService tagBaseService;

    @Autowired
    private TagChangeMsgProduct tagChangeMsgProduct;

    @Autowired
    private CdpTagAdapterServiceV2 cdpTagAdapterServiceV2;

    @Reference
    private PrivateSphereService privateSphereService;

    @Reference
    private TagTaskCoreService tagTaskCoreService;

    @Autowired
    private ArtemisService artemisService;

    @Reference
    private ExportService exportService;

    @Reference
    private OneCrmAdapterService oneCrmAdapterService;

    @Autowired
    private CustomerFacadeV2 customerFacadeV2;

    /**
     * 企微助手产品id
     */
    @Value("${aewc.productId:203}")
    private Long aewcProductId;

    /**
     * 企微助手产品id
     */
    @Value("${batch.query.customer.size:50}")
    private Integer batchQueryCustomerSize;

    @Autowired
    private RedissonClient redissonClient;

    @Value("${select.wid.size:200}")
    private Integer selectWidSize;

    @Autowired
    private CustomerTagSyncService customerTagSyncService;

    @Reference
    CustomerService customerService;

    @Resource
    EmployeeProxy employeeProxy;

    @Override
    public TagItemBO queryTagByProductInstanceId(TagQueryDTO tagQueryBOReq) {

        BasicInfo basicInfo = tagQueryBOReq.getBasicInfo();
        PrivateSphere privateSphere = privateSphereThird.fetchByBosId(basicInfo.getBosId());

        //获取bos下cdp产品实例
        List<ProductInstanceDTO> productInstanceDTOS = bosThird.queryProductInstanceDTO(privateSphere.getBosId(), Lists.newArrayList(204L));
        if (CollectionUtils.isEmpty(productInstanceDTOS)) {
            return null;
        }

        //获取cdp产品实例id
        ProductInstanceDTO cdpProductInstanceDTO = productInstanceDTOS.get(0);

        //查询bosId下根节点vid
        Long rootVid = bosThird.queryRootVidByBosId(privateSphere.getBosId());

        List<TagGroupBO> tagGroupBOList = cdpTagThird.queryAllTag(privateSphere.getBosId(), cdpProductInstanceDTO.getProductInstanceId(), rootVid);
        TagGroupConvert.fillCustomerTagUse(tagGroupBOList, null);
        if (CollectionUtils.isEmpty(tagGroupBOList)) {
            return null;
        }


        if (StringUtils.isNotBlank(tagQueryBOReq.getExternalUserId())) {
            Long wid = customerThird.getSuperWid(privateSphere.getBosId(), tagQueryBOReq.getExternalUserId(), privateSphere.getCorpId());
            if (Objects.isNull(wid)) {
                return TagGroupConvert.toTagItemBO(tagGroupBOList);
            }

            List<TagGroupBO> customerTagList = cdpTagThird.queryCustomerTag(privateSphere.getBosId(),
                    cdpProductInstanceDTO.getProductInstanceId(), rootVid, wid);
            if (CollectionUtils.isEmpty(tagGroupBOList)) {
                return TagGroupConvert.toTagItemBO(tagGroupBOList);
            }

            //获取给该客户打的标签id
            List<String> toCdpTagIds = TagGroupConvert.toCdpTagIds(customerTagList);

            //补充该用户是否打了标签
            TagGroupConvert.fillCustomerTagUse(tagGroupBOList, toCdpTagIds);
        }


        return TagGroupConvert.toTagItemBO(tagGroupBOList);
    }

    @Override
    public List<TagBO> queryCustomerTag(CustomerTagQueryDTO customerTagQueryDTO) {
        if (Objects.isNull(customerTagQueryDTO.getBosId())) {
            return new ArrayList<>();
        }

        BasicInfo basicInfo = new BasicInfo();
        basicInfo.setBosId(customerTagQueryDTO.getBosId());
        PrivateSphere privateSphere = privateSphereThird.fetch(basicInfo, true);

        //获取bos下cdp产品实例
        List<ProductInstanceDTO> productInstanceDTOS = bosThird.queryProductInstanceDTO(privateSphere.getBosId(), Lists.newArrayList(204L));
        if (CollectionUtils.isEmpty(productInstanceDTOS)) {
            return new ArrayList<>();
        }

        //获取cdp产品实例id
        ProductInstanceDTO cdpProductInstanceDTO = productInstanceDTOS.get(0);

        //查询bosId下根节点vid
        Long rootVid = bosThird.queryRootVidByBosId(privateSphere.getBosId());

        Long wid = customerTagQueryDTO.getWid();
        if (Objects.isNull(wid) && StringUtils.isNotBlank(customerTagQueryDTO.getExternalUserId())) {
            wid = customerThird.getSuperWid(privateSphere.getBosId(), customerTagQueryDTO.getExternalUserId(), privateSphere.getCorpId());
        }

        if (Objects.isNull(wid)) {
            return new ArrayList<>();
        }


        List<TagGroupBO> tagGroupBOList = cdpTagThird.queryCustomerTag(privateSphere.getBosId(),
                cdpProductInstanceDTO.getProductInstanceId(), rootVid, wid);
        if (CollectionUtils.isEmpty(tagGroupBOList)) {
            return new ArrayList<>();
        }

        return TagGroupConvert.toTagBO(tagGroupBOList);
    }

    @Override
    public SoaResponse<Boolean, ?> markTag(MarkTagDTO markTagBOReq) {

        //查询私域信息
        PrivateSphere privateSphere = privateSphereThird.fetchByBosId(markTagBOReq.getBosId());
        //检查私域信息
        commonCheckService.checkPrivateSphere(privateSphere);
        PrivateSphereDTO privateSphereDTO = PrivateSphereCovert.privateSphereDTO(privateSphere);


        //查询主客户wid
        Long wid = customerThird.getSuperWid(privateSphere.getBosId(), markTagBOReq.getExternalUserId(), privateSphere.getCorpId());
        if (Objects.isNull(wid)) {
            return SoaUtil.ok(false);
        }

        Customer customer = getCustomerId(privateSphere, markTagBOReq.getExternalUserId());

        Employee employee = null;
        if (markTagBOReq.getServerFrom() == 1) {
            employee = employeeProxy.fetchEmployeeById(privateSphere, markTagBOReq.getUserId(), null);
            if (Objects.isNull(employee)) {
                return SoaUtil.ok(false);
            }
        }

        List<TagAddDTO> tagList = markTagBOReq.getTagList();
        if (CollectionUtils.isEmpty(tagList)) {
            return SoaUtil.ok(false);
        }

        Map<String, Set<String>> cdpTagGroupIdMap = TagConvert.toCdpTagGroupIdAndCdpTagIdsMap(tagList);
        List<TagGroupBO> tagGroupBOList = cdpTagThird.queryTagByCdpTagIds(privateSphere.getBosId(), cdpTagGroupIdMap);
        Map<String, TagBO> cdpTagIdAndCdpTagGroupIdMap = TagConvert.toCdpTagIdAndTagBO(tagGroupBOList);

        List<TagDTO> tagDTOListAdd = new ArrayList<>();
        List<TagDTO> tagDTOListDelete = new ArrayList<>();
        for (TagAddDTO tagAddDTO : tagList) {

            TagBO tagBO = cdpTagIdAndCdpTagGroupIdMap.get(tagAddDTO.getCdpTagId());
            TagGroupDTO tagGroupDTO = new TagGroupDTO();
            tagGroupDTO.setCdpTagGroupId(tagAddDTO.getCdpTagGroupId());
            tagGroupDTO.setTagSource(tagAddDTO.getTagSource());
            if (Objects.nonNull(tagBO)) {
                TagGroupBO tagGroupBO = tagBO.getTagGroupBO();
                if (Objects.nonNull(tagGroupBO)) {
                    tagGroupDTO.setTagGroupName(tagGroupBO.getTagGroupName());
                }
            }

            TagDTO tagDTO = new TagDTO();
            tagDTO.setCdpTagId(tagAddDTO.getCdpTagId());
            tagDTO.setTagSource(tagAddDTO.getTagSource());
            tagDTO.setTagGroupDTO(tagGroupDTO);
            if (Objects.nonNull(tagBO)) {
                tagDTO.setTagName(tagBO.getTagName());
            }

            if (Objects.nonNull(tagAddDTO.getUse()) && !tagAddDTO.getUse()) {
                tagDTO.setOperateType(0);
                tagDTOListDelete.add(tagDTO);

            } else {
                tagDTO.setOperateType(1);
                tagDTOListAdd.add(tagDTO);
            }

        }

        CustomerTagDTO customerTagDTO = new CustomerTagDTO();
        customerTagDTO.setExternalUserId(markTagBOReq.getExternalUserId());
        customerTagDTO.setWid(wid);
        customerTagDTO.setPrivateSphereDTO(privateSphereDTO);
        if (markTagBOReq.getServerFrom() == 1 && Objects.nonNull(employee)) {
            customerTagDTO.setOrgUserId(employee.getId());
        }
        customerTagDTO.setUserId(markTagBOReq.getUserId());

        if (CollectionUtils.isNotEmpty(tagDTOListAdd)) {
            customerTagDTO.setTagDTOList(tagDTOListAdd);
            log.info("侧边栏客户画像打标, request:{}", JSON.toJSONString(customerTagDTO));
            SoaResponse<Boolean, ?> booleanSoaResponse = addCustomerTag(customerTagDTO);
            if (0 != Long.parseLong(booleanSoaResponse.getReturnCode())) {
                return booleanSoaResponse;
            }

            if (markTagBOReq.getServerFrom() == 1 && Objects.nonNull(employee)) {
                //添加跟进记录
                addOrUpdateActionLog(privateSphere, employee, customer, tagDTOListAdd, ActionLogEventTypeEnum.ADD_TAG);
            }


        }

        if (CollectionUtils.isNotEmpty(tagDTOListDelete)) {
            customerTagDTO.setTagDTOList(tagDTOListDelete);
            SoaResponse<Boolean, ?> booleanSoaResponse = removeCustomerTag(customerTagDTO, true);
            if (0L != Long.parseLong(booleanSoaResponse.getReturnCode())) {
                return booleanSoaResponse;
            }

            if (markTagBOReq.getServerFrom() == 1 && Objects.nonNull(employee)) {
                //添加跟进记录
                addOrUpdateActionLog(privateSphere, employee, customer, tagDTOListDelete, ActionLogEventTypeEnum.REMOVE_TAG);
            }

        }

        return SoaUtil.ok(true);
    }

    /**
     * 添加客户标签
     * 必须交验删除
     * 1、校验客户不能为空
     * 2、员工可以为空串，因为有些渠道打的标签是拿不到员工id的
     * 3、校验标签不能为空
     * 4、校验标签组不能为空
     *
     * @param customerTagDTO
     * @return
     */
    @Override
    public SoaResponse<Boolean, ?> addCustomerTag(CustomerTagDTO customerTagDTO) {
        log.info("添加客户标签, request:{}", JSON.toJSONString(customerTagDTO));

        List<TagDTO> tagDTOList = customerTagDTO.getTagDTOList();
        if (CollectionUtils.isEmpty(tagDTOList)) {
            return SoaUtil.ok(false);
        }

        PrivateSphere privateSphere = PrivateSphereCovert.toPrivateSphere(customerTagDTO.getPrivateSphereDTO());

        ProductInstanceDTO cdpProductInstance = bosThird.getCdpProductInstance(privateSphere.getBosId());
        Long rootVid = bosThird.queryRootVidByBosId(privateSphere.getBosId());
        if (Objects.isNull(cdpProductInstance) || Objects.isNull(rootVid)) {
            return SoaUtil.ok(false);
        }


        //检查私域信息
        commonCheckService.checkPrivateSphere(privateSphere);

        //检查外部联系人id，externalUSerId、customerId、wid
        tagCheckService.checkCustomer(privateSphere, customerTagDTO);

        //检查员工id
        tagCheckService.checkUser(privateSphere, customerTagDTO);

        //添加客户标签必须要有wid
        if (Objects.isNull(customerTagDTO.getWid())) {
            return SoaUtil.error(CUSTOMER_WID_IS_NOT_EMPTY.getCode(), CUSTOMER_WID_IS_NOT_EMPTY.getDesc(), false);
        }


        log.info("v1.4打标逻辑处理处理, request:{}", JSON.toJSONString(customerTagDTO));
        CustomerTagAdapterDTO customerTagAdapterDTO = new CustomerTagAdapterDTO();
        customerTagAdapterDTO.setWid(customerTagDTO.getWid());
        customerTagAdapterDTO.setOrgUserId(customerTagDTO.getOrgUserId());

        List<TagAdapterDTO> tagAdapterDTOS = new ArrayList<>();
        for (TagDTO tagDTO : tagDTOList) {

            TagGroupDTO tagGroupDTO = tagDTO.getTagGroupDTO();
            if (Objects.isNull(tagGroupDTO)) {
                continue;
            }

            TagAdapterDTO tagAdapterDTO = new TagAdapterDTO();
            tagAdapterDTO.setCdpTagId(tagDTO.getCdpTagId());

            TagGroupAdapterDTO tagGroupAdapterDTO = new TagGroupAdapterDTO();
            tagGroupAdapterDTO.setCdpTagGroupId(tagGroupDTO.getCdpTagGroupId());

            tagAdapterDTO.setTagGroupDTO(tagGroupAdapterDTO);

            tagAdapterDTOS.add(tagAdapterDTO);
        }

        customerTagAdapterDTO.setTagAdapterDTOS(tagAdapterDTOS);


        CdpRequest<List<CustomerTagAdapterDTO>> request = new CdpRequest<>();
        request.setData(Lists.newArrayList(customerTagAdapterDTO));
        request.setBosId(privateSphere.getBosId());
        request.setCdpProductInstanceId(cdpProductInstance.getProductInstanceId());
        request.setVid(rootVid);
        request.setOffline(customerTagDTO.getOffline());

        try {
            return cdpTagAdapterServiceV2.addCustomerTag(request);
        } catch (Exception e) {
            log.error("调用cdp服务打标失败, request:{}, error:{}", JSON.toJSONString(request), e);
            return SoaUtil.error(CDP_MARK_TAG_ERROR.getCode(), CDP_MARK_TAG_ERROR.getDesc(), false);
        }
    }

    /**
     * 移除客户标签不需要校验线束
     * 可以根据一下条件删除
     * 1、根据标签删除
     * 2、根据标签组删除
     * 3、根据员工删除
     * 4、根据客户删除
     *
     * @return
     */
    @Override
    public SoaResponse<Boolean, ?> removeCustomerTag(CustomerTagDTO customerTagDTO, Boolean manualMark) {

        PrivateSphere privateSphere = PrivateSphereCovert.toPrivateSphere(customerTagDTO.getPrivateSphereDTO());
        ProductInstanceDTO cdpProductInstance = bosThird.getCdpProductInstance(privateSphere.getBosId());
        Long rootVid = bosThird.queryRootVidByBosId(privateSphere.getBosId());
        if (Objects.isNull(cdpProductInstance) || Objects.isNull(rootVid)) {
            return SoaResponseUtil.ok(false);
        }

        //检查私域信息
        commonCheckService.checkPrivateSphere(privateSphere);

        //检查外部联系人id，externalUserId, customerId, wid
        tagCheckService.fillCustomer(privateSphere, customerTagDTO);

        //检查员工id
        tagCheckService.checkUser(privateSphere, customerTagDTO);

        List<TagDTO> tagDTOList = customerTagDTO.getTagDTOList();
        if (CollectionUtils.isEmpty(tagDTOList)) {
            return SoaResponseUtil.ok(false);
        }

        CustomerTagAdapterDTO customerTagAdapterDTO = new CustomerTagAdapterDTO();
        customerTagAdapterDTO.setWid(customerTagDTO.getWid());
        customerTagAdapterDTO.setOrgUserId(customerTagDTO.getOrgUserId());

        List<TagAdapterDTO> tagAdapterDTOS = new ArrayList<>();
        for (TagDTO tagDTO : tagDTOList) {

            TagGroupDTO tagGroupDTO = tagDTO.getTagGroupDTO();
            if (Objects.isNull(tagGroupDTO)) {
                continue;
            }

            TagAdapterDTO tagAdapterDTO = new TagAdapterDTO();
            TagGroupAdapterDTO tagGroupAdapterDTO = new TagGroupAdapterDTO();
            tagGroupAdapterDTO.setCdpTagGroupId(tagGroupDTO.getCdpTagGroupId());

            tagAdapterDTO.setTagGroupDTO(tagGroupAdapterDTO);
            tagAdapterDTO.setCdpTagId(tagDTO.getCdpTagId());

            tagAdapterDTOS.add(tagAdapterDTO);
        }
        customerTagAdapterDTO.setTagAdapterDTOS(tagAdapterDTOS);

        CdpRequest<CustomerTagAdapterDTO> request = new CdpRequest<>();
        request.setData(customerTagAdapterDTO);
        request.setBosId(privateSphere.getBosId());
        request.setCdpProductInstanceId(cdpProductInstance.getProductInstanceId());
        request.setVid(rootVid);
        request.setOffline(customerTagDTO.getOffline());

        try {
            return cdpTagAdapterServiceV2.removeCustomerTag(request);
        } catch (Exception e) {
            log.error("调用cdp服务移除客户标签失败, request:{}, error:{}", JSON.toJSONString(request), e);
            return SoaUtil.error(CDP_REMOVE_TAG_ERROR.getCode(), CDP_REMOVE_TAG_ERROR.getDesc(), false);
        }

    }

    @Override
    public Boolean initTag(PrivateSphere privateSphere, Boolean syncAllBosId) {

        if (Objects.isNull(privateSphere)) {
            return false;
        }

        //查询绑定该corpId的所有bosId
        Set<Long> bosIds = bosThird.getBosIdListByCorpId(privateSphere.getCorpId());

        //查询渠道corId下所有的企业官方标签
        List<CorpTagGroup> corpTagGroups = corpTagThird.queryCorpTagInfo(privateSphere, null, TagConstant.ALL);
        if (CollectionUtils.isEmpty(corpTagGroups)) {
            return false;
        }

        //校验一下，看本地是否有需要删除的标签组
        List<TagGroup> nativeTagGroupList = tagBaseService.queryGroupByCorpId(privateSphere.getCorpId());
        Set<String> remoteTagGroupIds = TagGroupConvert.toCorpTagGroupIds(corpTagGroups);
        Set<String> targetDeleteGroupIds = new HashSet<>();
        if (CollectionUtils.isNotEmpty(nativeTagGroupList)) {
            for (TagGroup tagGroup : nativeTagGroupList) {
                if (!remoteTagGroupIds.contains(tagGroup.getExternalTagGroupId())) {
                    targetDeleteGroupIds.add(tagGroup.getExternalTagGroupId());
                }
            }
        }

        //企微官方不存在该标签组了，但是企微助手本地还存在这个标签组，那就把该标签组删除掉，
        // 如果之前授权过，解绑了，又授权了，会存在这种问题
        if (CollectionUtils.isNotEmpty(targetDeleteGroupIds)) {
            batchDeleteTagGroup(privateSphere, Lists.newArrayList(targetDeleteGroupIds), syncAllBosId, bosIds);
        }

        //创建标签
        for (CorpTagGroup corpTagGroup : corpTagGroups) {
            initTagGroup(privateSphere, corpTagGroup, syncAllBosId, bosIds);
        }

        return true;

    }

    private void initTagGroup(PrivateSphere privateSphere, CorpTagGroup corpTagGroup, Boolean syncAllBosId, Set<Long> bosIds) {

        //创建标签组
        TagGroup tagGroup = buildTagGroup(privateSphere, corpTagGroup);
        tagBaseService.batchInsertTagGroup(Lists.newArrayList(tagGroup), privateSphere.getCorpId());

        List<CorpTagInfo> corpTagInfoList = corpTagGroup.getTagList();
        if (CollectionUtils.isEmpty(corpTagInfoList)) {
            return;
        }

        //与标签组同样的逻辑，企微官方不存在该标签了，但是企微助手本地还存在这个标签，那就把该标签删除掉，
        // 如果之前授权过，解绑了，又授权了，会存在这种问题
        Set<String> remoteCorpTagIds = TagConvert.toCorpTagIds(corpTagInfoList);
        List<Tag> nativeCorpTagList = tagBaseService.queryTagByGroupId(privateSphere.getCorpId(), corpTagGroup.getGroupId());
        Set<String> targetDeleteCorpTagIds = new HashSet<>();
        if (CollectionUtils.isNotEmpty(nativeCorpTagList)) {
            for (Tag tag : nativeCorpTagList) {
                if (!remoteCorpTagIds.contains(tag.getExternalTagId())) {
                    targetDeleteCorpTagIds.add(tag.getExternalTagId());
                }
            }
        }

        if (CollectionUtils.isNotEmpty(targetDeleteCorpTagIds)) {
            batchDeleteTag(privateSphere, Lists.newArrayList(targetDeleteCorpTagIds), syncAllBosId, bosIds);
        }

        batchInsertTag(privateSphere, corpTagInfoList, tagGroup);

        //同步cdp创建标签
        if (Objects.nonNull(syncAllBosId) && syncAllBosId) {
            for (Long bosId : bosIds) {
                tagChangeMsgProduct.sendTagCreateMsg(bosId, privateSphere.getCorpId(), corpTagGroup.getGroupId(), corpTagGroup.getGroupName(), corpTagInfoList);
            }
        } else {
            tagChangeMsgProduct.sendTagCreateMsg(privateSphere.getBosId(), privateSphere.getCorpId(), corpTagGroup.getGroupId(), corpTagGroup.getGroupName(), corpTagInfoList);
        }
    }

    private void batchDeleteTagGroup(PrivateSphere privateSphere, List<String> targetDeleteGroupIds, Boolean syncAllBosId, Set<Long> bosIds) {
        tagBaseService.deletedTagGroupByGroupIds(privateSphere.getCorpId(), Lists.newArrayList(targetDeleteGroupIds));

        //同步删除cdp删除标签组
        for (String targetDeleteGroupId : targetDeleteGroupIds) {
            if (Objects.nonNull(syncAllBosId) && syncAllBosId) {
                for (Long bosId : bosIds) {
                    tagChangeMsgProduct.sendTagDeleteMsg(bosId, privateSphere.getCorpId(), targetDeleteGroupId, null, TagChangeEnum.TAG_GROUP_DELETE.getType());
                }
            } else {
                tagChangeMsgProduct.sendTagDeleteMsg(privateSphere.getBosId(), privateSphere.getCorpId(), targetDeleteGroupId, null, TagChangeEnum.TAG_GROUP_DELETE.getType());
            }
        }
    }

    private void  batchDeleteTag(PrivateSphere privateSphere, List<String> targetDeleteCorpTagIds, Boolean syncAllBosId, Set<Long> bosIds) {
        tagBaseService.deletedTagByTagIds(privateSphere.getCorpId(), Lists.newArrayList(targetDeleteCorpTagIds));
        //同步cdp删除标签
        for (String targetDeleteTagId : targetDeleteCorpTagIds) {
            if (Objects.nonNull(syncAllBosId) && syncAllBosId) {
                for (Long bosId : bosIds) {
                    tagChangeMsgProduct.sendTagDeleteMsg(bosId, privateSphere.getCorpId(), null, targetDeleteTagId, TagChangeEnum.TAG_DELETE.getType());
                }
            } else {
                tagChangeMsgProduct.sendTagDeleteMsg(privateSphere.getBosId(), privateSphere.getCorpId(), null, targetDeleteTagId, TagChangeEnum.TAG_DELETE.getType());
            }
        }
    }

    private TagGroup buildTagGroup(PrivateSphere privateSphere, CorpTagGroup corpTagGroup) {
        TagGroup tagGroup = new TagGroup();
        tagGroup.setCorpId(privateSphere.getCorpId());
        tagGroup.setExternalTagGroupId(corpTagGroup.getGroupId());
        tagGroup.setTagGroupName(corpTagGroup.getGroupName());
        tagGroup.setTagSource(TagSourceEnum.WECHAT.getSource());
        tagGroup.setDeleted(false);
        tagGroup.setPrivateSphere(privateSphere);

        return tagGroup;
    }

    private void batchInsertTag(PrivateSphere privateSphere, List<CorpTagInfo> corpTagInfoList, TagGroup tagGroup) {
        List<Tag> tagList = buildTagList(privateSphere, corpTagInfoList, tagGroup);
        tagBaseService.batchInsertTag(tagList, privateSphere.getCorpId());
    }

    private List<Tag> buildTagList(PrivateSphere privateSphere, List<CorpTagInfo> corpTagInfoList, TagGroup tagGroup) {
        List<Tag> tagList = new ArrayList<>();
        for (CorpTagInfo corpTagInfo : corpTagInfoList) {
            Tag tag = new Tag();
            tag.setCorpId(privateSphere.getCorpId());
            tag.setTagGroup(tagGroup);
            tag.setExternalTagId(corpTagInfo.getTagId());
            tag.setTagName(corpTagInfo.getTagName());
            tag.setTagSource(TagSourceEnum.WECHAT.getSource());
            tag.setDeleted(false);
            tag.setPrivateSphere(privateSphere);

            tagList.add(tag);
        }
        return tagList;
    }

    @Override
    public Boolean initCustomerTag(PrivateSphere privateSphere, String externalUserId, SelfExternalContactGetBO selfExternalContactGetBO) {

        if (null == privateSphere) {
            return false;
        }


        //获取跟进外部联系人的所有员工，及标签
        if (selfExternalContactGetBO == null) {
            selfExternalContactGetBO = customerFacadeV2.queryTXCustomerInfo(privateSphere, externalUserId);
        }


        List<FollowUserBO> followUserList = null;
        if (null != selfExternalContactGetBO) {
            followUserList = selfExternalContactGetBO.getFollowUser();
        }


        //如果员工不存在，则直接返回
        if (CollectionUtils.isEmpty(followUserList)) {
            log.info("初始化客户标签, 客户没有关联的员工, privateSphere:{}, externalUserId:{}", JSON.toJSONString(privateSphere), externalUserId);
            return true;
        }


        for (FollowUserBO followUserBO : followUserList) {
            log.info("初始化客户标签, privateSphere:{}, externalUserId:{}, followUserBO:{}",
                    JSON.toJSONString(privateSphere), externalUserId, JSON.toJSONString(followUserBO));

            Employee employee = new Employee();
            employee.setTxUserId(followUserBO.getUserid());
            customerTagSyncService.syncCustomerTag(privateSphere, externalUserId, null, followUserList, employee);
        }


        return true;
    }

    @Override
    public Boolean batchMarkTag(ExternalUserInfoFindDTO externalUserInfoListDTO) {

        //1、check param
        MarkTagTaskCheck.checkMarkTag(externalUserInfoListDTO, selectWidSize);

        BasicInfo basicInfo = externalUserInfoListDTO.getBasicInfo();

        //幂等校验
        RLock lock = redissonClient.getLock(String.format(RedisKeyConstant.BATCH_MARK_TAG,
                basicInfo.getBosId(), externalUserInfoListDTO.getBwid()));


        try {
            // 加锁做幂等，最多等待0秒，上锁以后10秒自动解锁
            boolean lockResult = lock.tryLock(0, 2, TimeUnit.SECONDS);
            if (!lockResult) {
                log.warn("消费外部联系人原始消息幂等过滤的消息:{}", JSON.toJSONString(externalUserInfoListDTO));
                throw new BizException("存在未完成的任务，并发打标签");
            }
        } catch (Exception e) {
            log.error("批量打标签, 加锁失败, request:{}, error:{}", JSON.toJSONString(externalUserInfoListDTO), e);
            throw new BizException("打标失败");
        } finally {
            if (lock != null) {
                lock.unlock();
            }
        }


        externalUserInfoListDTO.setOperateType(TagOperateTypeEnum.ADD.getCode());

        return batchMarkTag(externalUserInfoListDTO, TagOperateTypeEnum.ADD.getCode());

    }

    @Override
    public Boolean batchRemoveTag(ExternalUserInfoFindDTO externalUserInfoListDTO) {

        //1、check param
        MarkTagTaskCheck.checkMarkTag(externalUserInfoListDTO, selectWidSize);
        externalUserInfoListDTO.setOperateType(TagOperateTypeEnum.REMOVE.getCode());

        BasicInfo basicInfo = externalUserInfoListDTO.getBasicInfo();

        //幂等校验
        RLock lock = redissonClient.getLock(String.format(RedisKeyConstant.BATCH_MARK_TAG,
                basicInfo.getBosId(), externalUserInfoListDTO.getBwid()));


        try {
            // 加锁做幂等，最多等待0秒，上锁以后10秒自动解锁
            boolean lockResult = lock.tryLock(0, 2, TimeUnit.SECONDS);
            if (!lockResult) {
                log.warn("消费外部联系人原始消息幂等过滤的消息:{}", JSON.toJSONString(externalUserInfoListDTO));
                throw new BizException("存在未完成的任务，并发打标签");
            }
        } catch (Exception e) {
            log.error("批量打标签, 加锁失败, request:{}, error:{}", JSON.toJSONString(externalUserInfoListDTO), e);
            throw new BizException("打标失败");
        } finally {
            if (lock != null) {
                lock.unlock();
            }
        }

        return batchMarkTag(externalUserInfoListDTO, TagOperateTypeEnum.REMOVE.getCode());
    }

    @Override
    public MarkTagInfoBO queryMarkTagInfo(MarkTagInfoDTO markTagInfoDTO) {

        //1、check param
        MarkTagTaskCheck.checkQueryMarkTagTask(markTagInfoDTO);

        PrivateSphere privateSphereRequest = new PrivateSphere();
        privateSphereRequest.setBosId(markTagInfoDTO.getBosId());
        privateSphereRequest.setProductId(aewcProductId);
        SoaResponse<PrivateSphere, Void> sphereVoidSoaResponse = privateSphereService.fetch(privateSphereRequest);
        if (0L != Long.parseLong(sphereVoidSoaResponse.getReturnCode())) {
            throw new BizException(Long.parseLong(sphereVoidSoaResponse.getReturnCode()), sphereVoidSoaResponse.getReturnMsg());
        }

        PrivateSphere privateSphere = sphereVoidSoaResponse.getResponseVo();
        if (null == privateSphere) {
            throw new BizException("查询私域不存在");
        }


        SingleRequest<MarkTagTask> request = new SingleRequest<>();
        MarkTagTask markTagTaskRequest = new MarkTagTask();
        markTagTaskRequest.setPrivateSphereId(privateSphere.getPrivateSphereId());
        markTagTaskRequest.setBwid(markTagInfoDTO.getBwid());

        request.setData(markTagTaskRequest);
        SoaResponse<MarkTagTask, Void> markTagTaskVoidSoaResponse = tagTaskCoreService.queryMarkTagTask(request);
        if (0L != Long.parseLong(markTagTaskVoidSoaResponse.getReturnCode())) {
            log.error("查询批量打标任务失败, request:{}, error:{}", JSON.toJSONString(request), markTagTaskVoidSoaResponse.getReturnMsg());
            return null;
        }

        MarkTagTask markTagTaskResult = markTagTaskVoidSoaResponse.getResponseVo();
        if (null == markTagTaskResult) {
            return null;
        }

        MarkTagInfoBO markTagInfoBO = new MarkTagInfoBO();
        markTagInfoBO.setPrivateSphereId(markTagTaskResult.getPrivateSphereId());
        markTagInfoBO.setTaskId(markTagTaskResult.getTaskId());
        markTagInfoBO.setBwid(markTagTaskResult.getBwid());
        markTagInfoBO.setTotalCount(markTagTaskResult.getTotalCount());
        markTagInfoBO.setStatus(markTagTaskResult.getStatus());

        Long failCount = markTagTaskResult.getFailCount();
        Long successCount = markTagTaskResult.getSuccessCount();

        markTagInfoBO.setFailCount(failCount);
        markTagInfoBO.setSuccessCount(successCount);

        Long currentExecuteCount = 0L;
        if (null != failCount) {
            currentExecuteCount += failCount;
        }

        if (null != successCount) {
            currentExecuteCount += successCount;
        }

        markTagInfoBO.setCurrentExecuteCount(currentExecuteCount);

        markTagInfoBO.setHaveRead(markTagTaskResult.getHaveRead());

        if (markTagTaskResult.getStatus().equals(MarkTagTaskStatusEnum.TASK_EXECUTE_SUCCESS.getStatus())) {
            markTagInfoBO.setFinish(true);
        } else {
            markTagInfoBO.setFinish(false);
        }

        //根据查询条件查人
        ExternalUserInfoFindDTO externalUserInfoFindDTO = JSONObject.parseObject(markTagTaskResult.getQuery(),
                ExternalUserInfoFindDTO.class);
        markTagInfoBO.setCdpTagGroupItemDTOS(externalUserInfoFindDTO.getTagList());
        markTagInfoBO.setOperateType(externalUserInfoFindDTO.getOperateType());

        return markTagInfoBO;
    }

    @Override
    public Boolean readMarkTagInfo(MarkTagInfoDTO markTagInfoDTO) {

        MarkTagTaskCheck.checkRead(markTagInfoDTO);

        PrivateSphere privateSphereRequest = new PrivateSphere();
        privateSphereRequest.setBosId(markTagInfoDTO.getBosId());
        privateSphereRequest.setProductId(aewcProductId);
        SoaResponse<PrivateSphere, Void> sphereVoidSoaResponse = privateSphereService.fetch(privateSphereRequest);
        if (0L != Long.parseLong(sphereVoidSoaResponse.getReturnCode())) {
            throw new BizException(Long.parseLong(sphereVoidSoaResponse.getReturnCode()), sphereVoidSoaResponse.getReturnMsg());
        }

        PrivateSphere privateSphere = sphereVoidSoaResponse.getResponseVo();
        if (null == privateSphere) {
            throw new BizException("查询私域不存在");
        }

        //查询任务，判断任务状态
        SingleRequest<MarkTagTask> request = new SingleRequest<>();
        MarkTagTask markTagTaskRequest = new MarkTagTask();
        markTagTaskRequest.setPrivateSphereId(privateSphere.getPrivateSphereId());
        markTagTaskRequest.setBwid(markTagInfoDTO.getBwid());
        markTagTaskRequest.setTaskId(markTagInfoDTO.getTaskId());

        request.setData(markTagTaskRequest);
        SoaResponse<MarkTagTask, Void> markTagTaskVoidSoaResponse = tagTaskCoreService.queryMarkTagTask(request);
        if (0L != Long.parseLong(markTagTaskVoidSoaResponse.getReturnCode())) {
            log.error("查询批量打标任务失败, request:{}, response:{}", JSON.toJSONString(request),
                    JSON.toJSONString(markTagTaskVoidSoaResponse));
            return null;
        }

        MarkTagTask markTagTaskResult = markTagTaskVoidSoaResponse.getResponseVo();
        if (null == markTagTaskResult) {
            return null;
        }

        if (!MarkTagTaskStatusEnum.TASK_EXECUTE_SUCCESS.getStatus().equals(markTagTaskResult.getStatus())) {
            log.error("任务打标未完成, task:{}", JSON.toJSONString(markTagTaskResult));
            throw new BizException("任务打标未完成");
        }

        //将该批任务更新为已读
        SingleRequest<MarkTagTask> updateMarkTagTask = new SingleRequest<>();
        MarkTagTask update = new MarkTagTask();
        update.setTaskId(markTagInfoDTO.getTaskId());
        update.setPrivateSphereId(privateSphere.getPrivateSphereId());
        update.setBwid(markTagInfoDTO.getBwid());
        update.setHaveRead(true);
        updateMarkTagTask.setData(update);

        SoaResponse<Boolean, Void> booleanVoidSoaResponse = tagTaskCoreService.updateMarkTagTask(updateMarkTagTask);
        if (0L != Long.parseLong(booleanVoidSoaResponse.getReturnCode())) {
            log.error("已读打标任务失败, 更新任务已读状态失败, request:{}, response:{}",
                    JSON.toJSONString(updateMarkTagTask), JSON.toJSONString(booleanVoidSoaResponse));
        }
        return true;
    }

    @Override
    public Boolean exportMarkTagFail(MarkTagInfoDTO markTagInfoDTO) {

        PrivateSphere privateSphereRequest = new PrivateSphere();
        privateSphereRequest.setBosId(markTagInfoDTO.getBosId());
        privateSphereRequest.setProductId(aewcProductId);
        SoaResponse<PrivateSphere, Void> sphereVoidSoaResponse = privateSphereService.fetch(privateSphereRequest);
        if (0L != Long.parseLong(sphereVoidSoaResponse.getReturnCode())) {
            throw new BizException(Long.parseLong(sphereVoidSoaResponse.getReturnCode()), sphereVoidSoaResponse.getReturnMsg());
        }

        PrivateSphere privateSphere = sphereVoidSoaResponse.getResponseVo();
        if (null == privateSphere) {
            throw new BizException("查询私域不存在");
        }

        // 4、创建导出任务
        ExportTaskSaveDTO exportTaskSaveDTO = new ExportTaskSaveDTO();
        exportTaskSaveDTO.setBosId(markTagInfoDTO.getBosId());
        exportTaskSaveDTO.setWid(markTagInfoDTO.getBwid());
        String dateStr = DateTimeFormatter.ofPattern("yyyyMMdd").format(LocalDate.now());
        exportTaskSaveDTO.setFileName("批量处理标签失败记录" + dateStr);
        exportTaskSaveDTO.setTaskType(ExportTaskTypeEnum.CUSTOMER_MARK_TAG_FAIL_RECORD_DOWNLOAD.getType());
        exportTaskSaveDTO.setVid(markTagInfoDTO.getVid());
        exportTaskSaveDTO.setProductId(aewcProductId);
        exportTaskSaveDTO.setParams(JsonUtil.obj2Str(markTagInfoDTO));
        SoaResponse<ExportTaskSaveVo, Void> exportTaskSaveVoVoidSoaResponse = exportService.saveExportTask(exportTaskSaveDTO);
        if (0L != Long.parseLong(exportTaskSaveVoVoidSoaResponse.getReturnCode())) {
            log.error("导出打标失败的客户标签关系失败, request:{}, error:{}", JSON.toJSONString(exportTaskSaveDTO), exportTaskSaveVoVoidSoaResponse.getReturnMsg());
            return false;
        }

        return true;
    }

    @Override
    public Long count(MarkTagInfoDTO markTagInfoDTO) {

        MarkTagTaskCheck.checkFetchCount(markTagInfoDTO);


        PrivateSphere privateSphereRequest = new PrivateSphere();
        privateSphereRequest.setBosId(markTagInfoDTO.getBosId());
        privateSphereRequest.setProductId(aewcProductId);
        SoaResponse<PrivateSphere, Void> sphereVoidSoaResponse = privateSphereService.fetch(privateSphereRequest);
        if (0L != Long.parseLong(sphereVoidSoaResponse.getReturnCode())) {
            throw new BizException(Long.parseLong(sphereVoidSoaResponse.getReturnCode()), sphereVoidSoaResponse.getReturnMsg());
        }

        PrivateSphere privateSphere = sphereVoidSoaResponse.getResponseVo();
        if (null == privateSphere) {
            throw new BizException("查询私域不存在");
        }

        SingleRequest<MarkTagDetail> request = new SingleRequest<>();
        MarkTagDetail markTagDetail = new MarkTagDetail();
        markTagDetail.setPrivateSphereId(privateSphere.getPrivateSphereId());
        markTagDetail.setTaskId(markTagInfoDTO.getTaskId());
        markTagDetail.setStatus(markTagInfoDTO.getStatus());
        markTagDetail.setBwid(markTagInfoDTO.getBwid());
        request.setData(markTagDetail);

        SoaResponse<Long, Void> countSoa = tagTaskCoreService.count(request);
        if (0L != Long.parseLong(countSoa.getReturnCode())) {
            log.error("查询打标明细总数失败, request:{}, response:{}", JSON.toJSONString(request), JSON.toJSONString(countSoa));
            return 0L;
        }

        return countSoa.getResponseVo();
    }

    @Override
    public List<CustomerMarkTagFailBO> queryMarkTagFailInfoExport(MarkTagInfoDTO markTagInfoDTO) {

        MarkTagTaskCheck.checkQueryMarkTagFailInfoExport(markTagInfoDTO);

        PrivateSphere privateSphereRequest = new PrivateSphere();
        privateSphereRequest.setBosId(markTagInfoDTO.getBosId());
        privateSphereRequest.setProductId(aewcProductId);
        SoaResponse<PrivateSphere, Void> sphereVoidSoaResponse = privateSphereService.fetch(privateSphereRequest);
        if (0L != Long.parseLong(sphereVoidSoaResponse.getReturnCode())) {
            throw new BizException(Long.parseLong(sphereVoidSoaResponse.getReturnCode()), sphereVoidSoaResponse.getReturnMsg());
        }

        PrivateSphere privateSphere = sphereVoidSoaResponse.getResponseVo();
        if (null == privateSphere) {
            throw new BizException("查询私域不存在");
        }

        SingleRequest<MarkTagTask> request = new SingleRequest<>();
        MarkTagTask markTagTask = new MarkTagTask();
        markTagTask.setTaskId(markTagInfoDTO.getTaskId());
        markTagTask.setPrivateSphereId(privateSphere.getPrivateSphereId());
        markTagTask.setDetailStatus(markTagInfoDTO.getStatus());
        markTagTask.setBwid(markTagInfoDTO.getBwid());
        request.setData(markTagTask);

        request.setPageSize(markTagInfoDTO.getPageSize());
        request.setPageNum(markTagInfoDTO.getPageNum());
        if (markTagInfoDTO.getNeedPage()) {
            request.setNeedPage(true);
        }
        SoaResponse<MultiResponse<MarkTagDetail>, Void> multiResponseVoidSoaResponse = tagTaskCoreService.
                queryMarkTagDetail(request);

        if (0L != Long.parseLong(multiResponseVoidSoaResponse.getReturnCode())) {
            log.error("导出打标失败信息失败, 查询打标详情失败, request:{}, response:{}",
                    JSON.toJSONString(request), JSON.toJSONString(multiResponseVoidSoaResponse));
            return new ArrayList<>();
        }

        MultiResponse<MarkTagDetail> responseVo = multiResponseVoidSoaResponse.getResponseVo();
        if (null == responseVo || CollectionUtils.isEmpty(responseVo.getDataList())) {
            log.error("导出打标失败信息失败, 查询打标详情未查到, request:{}, response:{}",
                    JSON.toJSONString(request), JSON.toJSONString(multiResponseVoidSoaResponse));
            return new ArrayList<>();
        }

        List<MarkTagDetail> markTagDetails = responseVo.getDataList();
        Set<String> customerIdSet = customerIdSet(markTagDetails);
        Map<String, Customer> customerIdAndNameMap = customerIdAndNameMap(Lists.newArrayList(customerIdSet), privateSphere.getCorpId(), privateSphere.getBosId());

        List<CustomerMarkTagFailBO> list = new ArrayList<>();
        for (MarkTagDetail markTagDetail : markTagDetails) {
            Customer customer = customerIdAndNameMap.get(markTagDetail.getCustomerId());

            CustomerMarkTagFailBO customerMarkTagFailBO = new CustomerMarkTagFailBO();
            customerMarkTagFailBO.setBosId(privateSphere.getBosId());
            customerMarkTagFailBO.setCustomerId(markTagDetail.getCustomerId());

            if (null != customer) {
                customerMarkTagFailBO.setName(customer.getName());
                customerMarkTagFailBO.setWid(customer.getWid());
            }

            customerMarkTagFailBO.setMessage(markTagDetail.getMessage());

            list.add(customerMarkTagFailBO);
        }


        return list;
    }

    private Set<String> customerIdSet(List<MarkTagDetail> markTagDetails) {
        if (CollectionUtils.isEmpty(markTagDetails)) {
            return new HashSet<>();
        }

        Set<String> customerIdSet = new HashSet<>();
        for (MarkTagDetail markTagDetail : markTagDetails) {
            customerIdSet.add(markTagDetail.getCustomerId());
        }

        return customerIdSet;
    }

    private Map<String, Customer> customerIdAndNameMap(List<String> customerIds, String corpId, Long bosId) {

        List<List<String>> partition = Lists.partition(customerIds, batchQueryCustomerSize);

        Map<String, Customer> customerIdAndNameMap = new HashMap<>();
        for (List<String> partitionCustomerIds : partition) {

            List<Customer> customerList;
            try {
                customerList = customerServiceProxy.fetchCustomerByIds(partitionCustomerIds, null, null);
                if (CollectionUtils.isEmpty(customerList)) {
                    continue;
                }
            } catch (Exception e) {
                log.error("查询客户基本信息失败, e", e);
                continue;
            }

            for (Customer customerRes : customerList) {

                try {

                    //1、获取外部联系人wid, 查询不到不退出
                    AccountGetDTO accountGetDTO = new AccountGetDTO();
                    accountGetDTO.setBosId(bosId);
                    accountGetDTO.setOpenId(customerRes.getExternalUserid());
                    accountGetDTO.setUcSourceTypeEnum(UCSourceTypeEnum.WORK_WEIXIN_EXTERNAL_USERID);
                    accountGetDTO.setAppId(corpId);


                    SoaResponse<AccountGetBO, ?> accountGetBOSoaResponse = oneCrmAdapterService.getAccountByOpenId(accountGetDTO);
                    AccountGetBO responseVo = accountGetBOSoaResponse.getResponseVo();
                    if (0L == Long.parseLong(accountGetBOSoaResponse.getReturnCode()) && null != responseVo) {
                        customerRes.setWid(responseVo.getWid());
                    }

                } catch (Exception e) {
                    log.warn("下载打标失败详情, 查询客户wid失败, bosId:{}, externalUserid:{}, error:{}", bosId, customerRes.getExternalUserid(), e);
                }


                customerIdAndNameMap.put(customerRes.getId(), customerRes);
            }
        }


        return customerIdAndNameMap;

    }

    private Boolean batchMarkTag(ExternalUserInfoFindDTO externalUserInfoListDTO, Integer operateType) {

        BasicInfo basicInfo = externalUserInfoListDTO.getBasicInfo();
        PrivateSphere privateSphereRequest = new PrivateSphere();
        privateSphereRequest.setBosId(basicInfo.getBosId());
        privateSphereRequest.setProductId(aewcProductId);
        SoaResponse<PrivateSphere, Void> sphereVoidSoaResponse = privateSphereService.fetch(privateSphereRequest);
        if (0L != Long.parseLong(sphereVoidSoaResponse.getReturnCode())) {
            throw new BizException(Long.parseLong(sphereVoidSoaResponse.getReturnCode()), sphereVoidSoaResponse.getReturnMsg());
        }

        PrivateSphere privateSphere = sphereVoidSoaResponse.getResponseVo();
        if (null == privateSphere) {
            throw new BizException("查询私域不存在");
        }

        //查询最近的任务，校验是否打标完成
        //查询任务
        SingleRequest<MarkTagTask> queryRequest = new SingleRequest<>();
        MarkTagTask queryTask = new MarkTagTask();
        queryTask.setPrivateSphereId(privateSphere.getPrivateSphereId());
        queryTask.setBwid(externalUserInfoListDTO.getBwid());
        queryRequest.setData(queryTask);
        SoaResponse<MarkTagTask, Void> markTagTaskVoidSoaResponse = tagTaskCoreService.queryMarkTagTask(queryRequest);
        if (0L != Long.parseLong(markTagTaskVoidSoaResponse.getReturnCode())) {
            log.error("打标失败, 查询任务失败, request:{}, response:{}", JSON.toJSONString(queryRequest), JSON.toJSONString(markTagTaskVoidSoaResponse));
            throw new BizException("存在未完成的任务，并发打标签");
        }

        MarkTagTask markTaskResponse = markTagTaskVoidSoaResponse.getResponseVo();
        if (null != markTaskResponse && !MarkTagTaskStatusEnum.TASK_EXECUTE_SUCCESS.getStatus().equals(markTaskResponse.getStatus())
                && !MarkTagTaskStatusEnum.INIT_TASK_FAIL.getStatus().equals(markTaskResponse.getStatus())) {
            log.error("打标失败, 上次任务进行中, request:{}, response:{}", JSON.toJSONString(queryRequest), markTaskResponse);
            throw new BizException("存在未完成的任务，并发打标签");
        }

        //2、存储任务批次
        SingleRequest<MarkTagTask> request = new SingleRequest<>();
        MarkTagTask markTagTask = new MarkTagTask();
        markTagTask.setBwid(externalUserInfoListDTO.getBwid());
        markTagTask.setPrivateSphereId(privateSphere.getPrivateSphereId());
        markTagTask.setStatus(MarkTagTaskStatusEnum.CREATE_TASK.getStatus());
        markTagTask.setQuery(JSON.toJSONString(externalUserInfoListDTO));
        markTagTask.setDeleted(false);
        markTagTask.setCreateTime(new Date());
        markTagTask.setUpdateTime(new Date());

        request.setData(markTagTask);

        SoaResponse<MarkTagTask, Void> insertMarkTagTaskSoa = tagTaskCoreService.insertMarkTagTask(request);
        if (0L != Long.parseLong(insertMarkTagTaskSoa.getReturnCode())) {
            log.error("创建任务失败, request:{}, response:{}", JSON.toJSONString(request), JSON.toJSONString(insertMarkTagTaskSoa));
            throw new BizException("创建任务失败");
        }

        MarkTagTask responseVo = insertMarkTagTaskSoa.getResponseVo();
        if (null == responseVo || null == responseVo.getTaskId()) {
            log.error("创建任务失败, 没有生成任务id, request:{}", JSON.toJSONString(request));
            throw new BizException("创建打标任务失败");
        }

        MarkTagTaskMessage markTagTaskMessage = new MarkTagTaskMessage();
        markTagTaskMessage.setTaskId(responseVo.getTaskId());
        markTagTaskMessage.setBosId(privateSphere.getBosId());
        markTagTaskMessage.setBwid(externalUserInfoListDTO.getBwid());
        markTagTaskMessage.setOperateType(operateType);

        //3、发送消息
        ArtemisBaseInfo<MarkTagTaskMessage> artemisBaseInfo = new ArtemisBaseInfo<>();
        artemisBaseInfo.setTopic(ArtemisConstant.Topic.WECHATWORK_BATCH_MARK_TAG_TASK_INIT_TOPIC);
        artemisBaseInfo.setEvent(markTagTaskMessage);
        artemisBaseInfo.setProducer(ArtemisConstant.USER);
        return artemisService.sendToArtemis(artemisBaseInfo, privateSphere.getBosId());
    }


    private void addOrUpdateActionLog(PrivateSphere privateSphere, Employee employee, Customer customer, List<TagDTO> tagDTOList, ActionLogEventTypeEnum eventType) {
        if (CollectionUtils.isEmpty(tagDTOList)) {
            return;
        }

        List<TagDTO> afterFilterTagDTOList = TagConvert.filterTagNameForNull(tagDTOList);
        if (CollectionUtils.isEmpty(afterFilterTagDTOList)) {
            return;
        }

        StringBuilder actionLogStr = new StringBuilder();

        for (TagDTO tagDTO : afterFilterTagDTOList) {
            actionLogStr.append(tagDTO.getTagName()).append(",");
        }
        actionLogStr.deleteCharAt(actionLogStr.length() - 1);
        //避免落库失败，截取前300个字符，超过用...代替
        String actionValue = actionLogStr.toString();
        if (actionValue.length() > Constants.ACTION_VALUE_LENGTH) {
            actionValue = actionValue.substring(0, Constants.ACTION_VALUE_LENGTH) + Constants.ACTION_VALUE_END_OF;
        }
        // 添加跟进记录
        ActionLog actionLog = new ActionLog();
        actionLog.setCorpId(privateSphere.getCorpId());
        actionLog.setPrivateSphereId(privateSphere.getPrivateSphereId());
        actionLog.setMaster(employee);
        actionLog.setFollower(customer);
        actionLog.setBizType(ActionLogBizeTypeEnum.TRACK_RECORD);
        actionLog.setEventType(eventType);
        actionLog.setActionTime(new Date());
        actionLog.setActionValue(actionValue);
        actionLog.setActionDesc(String.format(eventType.getDesc(), actionValue));
        customerService.createActionLog(actionLog);
    }


    public Customer getCustomerId(PrivateSphere privateSphere, String externalUserId) {
        try {
            List<Customer> customerResponses = customerServiceProxy.fetchCustomerByIds(null, externalUserId, privateSphere);
            if (CollectionUtils.isEmpty(customerResponses)) {
                return null;
            }
            return customerResponses.get(0);
        } catch (Exception e) {
            log.error("根据externalUserId查询客户失败, externalUserId:{}, e", externalUserId, e);
            return null;
        }
    }
}
